"""Geometry helpers for ROI and distances."""
from __future__ import annotations
from typing import List, Tuple
import math


def point_in_polygon(pt: Tuple[int, int], poly: List[Tuple[int, int]]) -> bool:
    # Ray casting algorithm (minimal impl)
    x, y = pt
    inside = False
    n = len(poly)
    for i in range(n):
        x1, y1 = poly[i]
        x2, y2 = poly[(i + 1) % n]
        if ((y1 > y) != (y2 > y)) and (x < (x2 - x1) * (y - y1) / (y2 - y1 + 1e-9) + x1):
            inside = not inside
    return inside


def _dist_point_to_segment(p: Tuple[int, int], a: Tuple[int, int], b: Tuple[int, int]) -> float:
    # distance from point p to segment ab
    (px, py), (x1, y1), (x2, y2) = p, a, b
    vx, vy = x2 - x1, y2 - y1
    wx, wy = px - x1, py - y1
    c1 = vx * wx + vy * wy
    if c1 <= 0:
        return math.hypot(px - x1, py - y1)
    c2 = vx * vx + vy * vy
    if c2 <= 0:
        return math.hypot(px - x1, py - y1)
    t = c1 / c2
    if t >= 1:
        return math.hypot(px - x2, py - y2)
    projx, projy = x1 + t * vx, y1 + t * vy
    return math.hypot(px - projx, py - projy)


def min_distance_point_to_polygon(p: Tuple[int, int], poly: List[Tuple[int, int]]) -> float:
    if point_in_polygon(p, poly):
        return 0.0
    d = float("inf")
    n = len(poly)
    for i in range(n):
        a, b = poly[i], poly[(i + 1) % n]
        d = min(d, _dist_point_to_segment(p, a, b))
    return d


def center_of_bbox(b: Tuple[int, int, int, int]) -> Tuple[int, int]:
    x1, y1, x2, y2 = b
    return int((x1 + x2) / 2), int((y1 + y2) / 2)


def approx_distance_polygon_to_bbox(poly: List[Tuple[int, int]], bbox_xyxy: Tuple[int, int, int, int]) -> float:
    # Approximate distance using center-to-polygon
    c = center_of_bbox(bbox_xyxy)
    return min_distance_point_to_polygon(c, poly)


def center_distance(a: Tuple[int, int], b: Tuple[int, int]) -> float:
    return math.hypot(a[0] - b[0], a[1] - b[1])
